#include "rkmedia_data_process.h"

extern videoQueue *high_video_queue;
extern videoQueue *low_video_queue;
extern containerInfo *above_container_func;
extern audioQueue *audio_queue;

extern pthread_mutex_t push_mutex;

AVPacket *put_high_video_to_ffmpeg_avpacket(AVPacket *pPacket)
{
    int ret = -1;
    video_data_packet *highPacket = high_video_queue->getVideoDataFromQueue();
    if (!highPacket)
    {
        cout << "highPacket is null..." << endl;
        return NULL;
    }
    else
    {
        //av_packet_unref(pPacket);
        ret = av_buffer_realloc(&pPacket->buf, highPacket->buffer_size + 100);
        if (ret)
        {
            cout << "high av_buffer_realloc failed ..." << endl;
            return NULL;
        }
        else
        {
            // cout << "high av_buffer_realloc success ..." << endl;
            pPacket->size = highPacket->buffer_size;
            memcpy(pPacket->buf->data, highPacket->buffer, highPacket->buffer_size);
            pPacket->data = pPacket->buf->data; // 数据缓冲
            pPacket->flags |= AV_PKT_FLAG_KEY;
            delete[] highPacket->buffer;
            delete highPacket;
            highPacket = NULL;
            return pPacket;
        }
    }
}

AVPacket *put_low_video_to_ffmpeg_avpacket(AVPacket *pPacket)
{
    int ret = -1;
    video_data_packet *lowPacket = low_video_queue->getVideoDataFromQueue();
    if (!lowPacket)
    {
        cout << "lowPacket is null..." << endl;
        return NULL;
    }
    else
    {
        // av_packet_unref(pPacket);
        ret = av_buffer_realloc(&pPacket->buf, lowPacket->buffer_size + 100);
        if (ret)
        {
            cout << "low av_buffer_realloc failed ..." << endl;
            return NULL;
        }
        else
        {
            // cout << "low av_buffer_realloc success ..." << endl;
            pPacket->size = lowPacket->buffer_size;
            memcpy(pPacket->buf->data, lowPacket->buffer, lowPacket->buffer_size);
            pPacket->data = pPacket->buf->data; // 数据缓冲
            pPacket->flags |= AV_PKT_FLAG_KEY;
            delete[] lowPacket->buffer;
            delete lowPacket;
            lowPacket = NULL;
            return pPacket;
        }
    }
}

AVPacket *put_audio_to_ffmpeg_avpacket(AVPacket *pPacket)
{
    int ret = -1;
    audio_data_packet *pkt = audio_queue->getAudioDataFromQueue();
    if (!pkt)
    {
        cout << "audio Packet is null..." << endl;
        return NULL;
    }
    else
    {
        // av_packet_unref(pPacket);
        ret = av_buffer_realloc(&pPacket->buf, pkt->buffer_size + 100);
        if (ret)
        {
            cout << "audio av_buffer_realloc failed ..." << endl;
            return NULL;
        }
        else
        {
            // cout << "audio av_buffer_realloc success ..." << endl;
            pPacket->size = pkt->buffer_size;
            memcpy(pPacket->buf->data, pkt->buffer, pkt->buffer_size);
            pPacket->data = pPacket->buf->data; // 数据缓冲

            // pPacket->duration = 1;
            // pPacket->duration = pPacket->size / (2 * av_get_bytes_per_sample(AV_SAMPLE_FMT_FLTP));
            delete[] pkt->buffer;
            delete pkt;
            pkt = NULL;
            return pPacket;
        }
    }
}
/*
int per_convert_write_avpacket_to_context(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt)
{
    av_packet_rescale_ts(pkt, *time_base, st->time_base);
    pkt->stream_index = st->index;
    return av_interleaved_write_frame(fmt_ctx, pkt); // ！！！这个返回值用来判断是否正常写入帧，而无论是否成功写入，                                                    // libavformat都会负责释放传入的AVPacket                                                   // 如果加了判断加入加了return,有可能会因为DTS不是单调递增问题导致报错.....
}
*/
int deal_high_video_avpacket(AVFormatContext *fmt_ctx, OutputStream *ost)
{
    int ret = -1;
    AVCodecContext *tmp = ost->ctx;
    AVPacket *high_video_packet = put_high_video_to_ffmpeg_avpacket(ost->pkt); // 因为再把视频流写道avpacket中时，已经给AVStreamRef进行realloc
    if (high_video_packet != NULL)
    {
        high_video_packet->stream_index = 0;
        // high_video_packet->duration = 1000 / 30;
        high_video_packet->pts = av_rescale_q(ost->timestamp, (AVRational){1, 1000000}, fmt_ctx->streams[0]->time_base);
        high_video_packet->dts = high_video_packet->pts;
        ost->timestamp++;
    }
    av_interleaved_write_frame(fmt_ctx, high_video_packet);
    av_packet_unref(high_video_packet);
   
    return 0;
}

int deal_low_video_avpacket(AVFormatContext *fmt_ctx, OutputStream *ost)
{
    int ret = -1;
    AVCodecContext *tmp = ost->ctx;
    AVPacket *low_video_packet = put_low_video_to_ffmpeg_avpacket(ost->pkt); // 因为再把视频流写道avpacket中时，已经给AVStreamRef进行realloc
    if (low_video_packet != NULL)
    {
        low_video_packet->stream_index = 0;
        // low_video_packet->duration = 1000 / 30;
        low_video_packet->pts = av_rescale_q(ost->timestamp, (AVRational){1, 1000000}, fmt_ctx->streams[0]->time_base);
        low_video_packet->dts = low_video_packet->pts;
        low_video_packet->pts = ost->timestamp++;
    } 
    av_interleaved_write_frame(fmt_ctx, low_video_packet);
    av_packet_unref(low_video_packet);

    return 0;
}

int deal_audio_avpacket(AVFormatContext *fmt_ctx, OutputStream *ost)
{
    int ret = -1;
    AVCodecContext *tmp = ost->ctx;
    AVPacket *pkt = put_audio_to_ffmpeg_avpacket(ost->pkt); // 因为再把视频流写道avpacket中时，已经给AVStreamRef进行realloc

    if (pkt != NULL)
    {
        pkt->stream_index = 1;
        // pkt->flags |= AV_PKT_FLAG_KEY;
        //  pkt->duration = 1000 * 1024 / 48000;
        pkt->pts = av_rescale_q(ost->timestamp * 1024, (AVRational){1, 48000}, fmt_ctx->streams[1]->time_base);
        pkt->dts = pkt->pts;
        ost->timestamp++;
    }

    av_interleaved_write_frame(fmt_ctx, pkt);
    av_packet_unref(pkt);
    return 0;
}

#if 1
void *camera_venc_thread(void *args)
{
    pthread_detach(pthread_self());
    MEDIA_BUFFER mb;
    RV1126_VENC_CONTAINER venc_container;
    above_container_func->get_venc_container(0, &venc_container);
    printf("venc_chn is %d\n", venc_container.venc_chn);
    // FILE *fd = fopen("123.nv12", "w+");
    while (1)
    {
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, venc_container.venc_chn, -1);
        if (!mb)
        {
            printf("Get venc mb failed...\n");
            return NULL;
        }
        else
        {
            // printf("Get venc mb success...\n");
            video_data_packet *high_video_packet = new video_data_packet;
            high_video_packet->buffer = new unsigned char[RK_MPI_MB_GetSize(mb)];
            memcpy(high_video_packet->buffer, RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb));
            high_video_packet->buffer_size = RK_MPI_MB_GetSize(mb);
            high_video_queue->putVideoDataToQueue(high_video_packet);

            // fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, fd);
            RK_MPI_MB_ReleaseBuffer(mb);
        }
    }
    return NULL;
}

void *ffmpeg_high_video_push_thread(void *args)
{
    pthread_detach(pthread_self());
    int ret = -1;
    ffmpegInfo ffmpeg_config = *(ffmpegInfo *)args;
    //delete (ffmpegInfo *)args;
    //args = NULL;
    while (1)
    {
        pthread_mutex_lock(&push_mutex);
        ret = deal_high_video_avpacket(ffmpeg_config.fmt_ctx, &ffmpeg_config.video_stream);
        pthread_mutex_unlock(&push_mutex);

        // av_usleep(1000000 * 1 / 30);

        if (ret)
        {
            cout << "ffmpeg_high_video_push_thread exist error..." << endl;
            break;
        }
    }
    pthread_mutex_lock(&push_mutex);
    if (args != NULL)
    {
        delete (ffmpegInfo *)args;
        args = NULL;
    }
    pthread_mutex_unlock(&push_mutex);
    av_write_trailer(ffmpeg_config.fmt_ctx);
    free_stream(&ffmpeg_config.video_stream);
    free_stream(&ffmpeg_config.audio_stream);
    avio_closep(&ffmpeg_config.fmt_ctx->pb);      // 关闭AVIOContext
    avformat_free_context(ffmpeg_config.fmt_ctx); // 释放这个AVFormatContext以及和它关联的所有Stream
    return NULL;
}
#endif

#if 0
void *camera_rga_thread(void *args)
{
    pthread_detach(pthread_self());
    MEDIA_BUFFER mb;
    RV1126_RGA_CONTAINER rga_container;
    above_container_func->get_rga_container(0, &rga_container);
    printf("rga_chn is %d\n", rga_container.rga_chn);
    while (1)
    {
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_RGA, rga_container.rga_chn, -1);
        if (!mb)
        {
            printf("Get rga mb failed...\n");
            break;
        }
        else
        {
            // printf("Get rga mb success...\n");
            RK_MPI_SYS_SendMediaBuffer(RK_ID_VENC, 1, mb);
            RK_MPI_MB_ReleaseBuffer(mb);
        }
    }
    return NULL;
}

void *camera_low_venc_thread(void *args)
{
    pthread_detach(pthread_self());
    MEDIA_BUFFER mb;
    RV1126_VENC_CONTAINER low_venc_container;
    above_container_func->get_venc_container(1, &low_venc_container);
    printf("low_venc_chn is %d\n", low_venc_container.venc_chn);
    //FILE *fd = fopen("123.nv12", "w+");
    while (1)
    {
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, low_venc_container.venc_chn, -1);
        if (!mb)
        {
            printf("Get low_venc mb failed...\n");
            return NULL;
        }
        else
        {
            // printf("Get low_venc mb success...\n");
            video_data_packet *low_video_packet = new video_data_packet;
            low_video_packet->buffer = new unsigned char[RK_MPI_MB_GetSize(mb)];
            memcpy(low_video_packet->buffer, RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb));
            low_video_packet->buffer_size = RK_MPI_MB_GetSize(mb);
            low_video_queue->putVideoDataToQueue(low_video_packet);

           // fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, fd);

            RK_MPI_MB_ReleaseBuffer(mb);
        }
    }
    return NULL;
}

void *ffmpeg_low_video_push_thread(void *args)
{
    pthread_detach(pthread_self());
    int ret = -1;
    ffmpegInfo ffmpeg_config = *(ffmpegInfo *)args;
    delete (ffmpegInfo *)args;
    //args = NULL;
    while (1)
    {
      //  pthread_mutex_lock(&push_mutex);
        ret = deal_low_video_avpacket(ffmpeg_config.fmt_ctx, &ffmpeg_config.video_stream);
       // pthread_mutex_unlock(&push_mutex);
        if (ret)
        {
            cout << "ffmpeg_low_video_push_thread exist error..." << endl;
            break;
        }
    }
    /*
    pthread_mutex_lock(&push_mutex);
    if (args != NULL)
    {
        delete (ffmpegInfo *)args;
        args = NULL;
    }
    pthread_mutex_unlock(&push_mutex);*/
    av_write_trailer(ffmpeg_config.fmt_ctx);
    free_stream(&ffmpeg_config.video_stream);
    free_stream(&ffmpeg_config.audio_stream);
    avio_closep(&ffmpeg_config.fmt_ctx->pb);      // 关闭AVIOContext
    avformat_free_context(ffmpeg_config.fmt_ctx); // 释放这个AVFormatContext以及和它关联的所有Stream
    return NULL;
}
#endif

#if 1
void *mic_aenc_thread(void *args)
{
    pthread_detach(pthread_self());
    MEDIA_BUFFER mb;
    RV1126_AENC_CONTAINER aenc_container;
    above_container_func->get_aenc_container(0, &aenc_container);
    cout << "aenc_chn is " << aenc_container.aenc_chn << endl;
    // FILE *fd = fopen("123.aac", "w+");
    while (1)
    {
        mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_AENC, aenc_container.aenc_chn, -1);
        if (!mb)
        {
            cout << "Get aenc mb failed ..." << endl;
            return NULL;
        }
        else
        {
            // cout << "Get aenc mb success ..." << endl;
            audio_data_packet *pkt = new audio_data_packet;
            pkt->buffer = new unsigned char[RK_MPI_MB_GetSize(mb)];
            pkt->buffer_size = RK_MPI_MB_GetSize(mb);
            memcpy(pkt->buffer, RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb));
            audio_queue->putAudioDataToQueue(pkt);

            // fwrite(RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetSize(mb), 1, fd);

            RK_MPI_MB_ReleaseBuffer(mb);
        }
    }
    return NULL;
}

void *audio_push_thread(void *args)
{
    pthread_detach(pthread_self());
    int ret = -1;
    ffmpegInfo ffmpeg_config = *(ffmpegInfo *)args;

    while (1)
    {
        pthread_mutex_lock(&push_mutex);
        ret = deal_audio_avpacket(ffmpeg_config.fmt_ctx, &ffmpeg_config.audio_stream);
        pthread_mutex_unlock(&push_mutex);

        // av_usleep(1000000 * 1024 / 48000);

        if (ret)
        {
            cout << "audio ffmpeg_high_video_push_thread exist error..." << endl;
            break;
        }
    }
    pthread_mutex_lock(&push_mutex);
    if (args != NULL)
    {
        delete (ffmpegInfo *)args;
        args = NULL;
    }
    pthread_mutex_unlock(&push_mutex);
    av_write_trailer(ffmpeg_config.fmt_ctx);
    free_stream(&ffmpeg_config.video_stream);
    free_stream(&ffmpeg_config.audio_stream);
    avio_closep(&ffmpeg_config.fmt_ctx->pb);      // 关闭AVIOContext
    avformat_free_context(ffmpeg_config.fmt_ctx); // 释放这个AVFormatContext以及和它关联的所有Stream
    return NULL;
}

#endif